Android OpenGLES 绘制三角形 ,四边形

  1. 验证是否支持OpenGLES2.0
1
2
3
4
//检查设备是否支持OpenGL ES 2.0
final ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportES2 = configurationInfo.reqGlEsVersion >= 0x00020000;

确保可用,在manifest里面添加验证

1
<uses-feature android:glEsVersion="0x00020000" android:required="true" />

  1. 定义vertex_shader.glslfragment_shader.glslres/raw里面

vertex_shader.glsl

1
2
3
4
attribute vec4 vPosition;
void main(){
gl_Position = vPosition;
}

fragment_shader.glsl

1
2
3
4
5
precision mediump float;
uniform vec4 vColor;
void main(){
gl_FragColor = vColor;
}

OpenGL ES Shader的三种变量类型uniform,attribute和varying

  1. 定义形状
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import android.content.Context;
import android.opengl.GLES20;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class Triangle {

//坐标本地内存地址
private FloatBuffer vertexBuffer;

//每一次取点的时候取几个点
static final int COORDS_PER_VERTEX = 3;

//绘制坐标
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};

// Set color with red, green, blue and alpha (opacity) values
float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};


private final int mProgram;

private int mPositionHandle;
private int mColorHandle;

private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
//每一次取的总的点 大小
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

public Triangle(Context context) {
//为坐标分配本地内存地址
vertexBuffer = ByteBuffer
.allocateDirect(triangleCoords.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(triangleCoords);
vertexBuffer.position(0);

//根据shader代码和fragment代码 获取到一个渲染程序
mProgram = ShaderUtil.createProgram(ShaderUtil.readRawTxt(context, R.raw.vertex_shader),
ShaderUtil.readRawTxt(context, R.raw.fragment_shader));
if (mProgram > 0) {
//获取vertex shader的属性vPosition 的地址
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
//获取fragment shader的属性vColor 的地址
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
}
}


public void draw() {
//使用渲染程序
GLES20.glUseProgram(mProgram);

// 使顶点属性数组有效
GLES20.glEnableVertexAttribArray(mPositionHandle);

// 为顶点属性赋值
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);

// 设置颜色
GLES20.glUniform4fv(mColorHandle, 1, color, 0);

// 绘制图形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

// 禁用顶点数组
GLES20.glDisableVertexAttribArray(mPositionHandle);

}
}

顶点坐标系

ShaderUtil.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

import android.content.Context;
import android.opengl.GLES20;
import android.util.Log;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class ShaderUtil {
private static final String TAG = "ShaderUtil";


public static String readRawTxt(Context context, int rawId) {
InputStream inputStream = context.getResources().openRawResource(rawId);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer sb = new StringBuffer();
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}

public static int loadShader(int shaderType, String source) {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(shaderType);
if (shader != 0) {
//添加代码到shader
GLES20.glShaderSource(shader, source);
//编译shader
GLES20.glCompileShader(shader);
int[] compile = new int[1];
//检测是否编译成功
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compile, 0);
if (compile[0] != GLES20.GL_TRUE) {
Log.d(TAG, "shader compile error");
GLES20.glDeleteShader(shader);
shader = 0;
}
}
return shader;
}

public static int createProgram(String vertexSource, String fragmentSource) {
//获取vertex shader
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0) {
return 0;
}
//获取fragment shader
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
if (fragmentShader == 0) {
return 0;
}
//创建一个空的渲染程序
int program = GLES20.glCreateProgram();
if (program != 0) {
//添加vertexShader到渲染程序
GLES20.glAttachShader(program, vertexShader);
//添加fragmentShader到渲染程序
GLES20.glAttachShader(program, fragmentShader);
//关联为可执行渲染程序
GLES20.glLinkProgram(program);
int[] linsStatus = new int[1];
//检测是否关联成功
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linsStatus, 0);
if (linsStatus[0] != GLES20.GL_TRUE) {
Log.d(TAG, "link program error");
GLES20.glDeleteProgram(program);
program = 0;
}
}
return program;

}

}
  1. 定义shader

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39

    import android.content.Context;
    import android.opengl.GLES20;
    import android.opengl.GLSurfaceView;

    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;

    public class MyRender implements GLSurfaceView.Renderer {

    private Context context;

    private Triangle triangle;

    public MyRender(Context context) {
    this.context = context;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    triangle = new Triangle(context);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
    //宽高
    GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
    //清空颜色
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    //设置背景颜色
    // GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    triangle.draw();
    }
    }
  2. 设置shaderGLSurfaceView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;

public class MyGLSurfaceView extends GLSurfaceView{

public MyGLSurfaceView(Context context) {
this(context, null);
}

public MyGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setEGLContextClientVersion(2);
setRenderer(new MyRender(context));
}
}

上述三角形已经绘制成功。

  1. 绘制四边形
    绘制四边形的方式是由两个三角形形成一个四边形,所以顶点位置一定要注意。
    调用GLES20.glDrawArrays的时候设置flog可以设置为GLES20.GL_TRIANGLE_STRIPGLES20.GL_TRIANGLES,前者复用坐标,后者分别取几个坐标。
    绘制四边形
-------------The End-------------